package iSOCK::Controller::Root;

use Moose;
use namespace::autoclean;

BEGIN { extends 'Catalyst::Controller' }

use DateTime;
use File::Slurp qw( slurp );
use SOCK;
use iSOCK;

=head1 NAME

iSOCK::Controller::Root - Root Controller for iSOCK

=head1 DESCRIPTION

[enter your description here]

=head1 METHODS

=cut

=head2 default

=cut

sub default : Path('/') {
  my ( $self, $c ) = @_;

  $c->response->redirect ( $c->uri_for ( $c->config->{default_path} ) );
}

sub transparent : Regex('^/?tmp/[0-9a-z]{40}/') {}

sub auto : Private {
  my ( $self, $c ) = @_;
  
  if ( $c->request->action ne 'login' ) {
    $c->model ( 'App' )->alter_session ({ c => $c });
  }
  
  return 1;
}

sub end : ActionClass('RenderView') {}

sub feed : Path('/feed/sock') {
  my ( $self, $c ) = @_;
  
  $c->stash->{feed} = slurp ( $c->path_to ( 'root', 'SOCK' ) . '/doc/release_feed.xml' );
  
  $c->forward ( 'View::Feed' );
}

sub render_view : Private {
  my ( $self, $c ) = @_;
  
  my $action = $c->request->action;

  #
  # Login.
  #

  if ( !$c->user && $action !~ /^(login|logout)$/ ) {
    $self->bounce_to ( $c => '/login' );
  }

  #
  # Session.
  #
  
  my ( $session, $session_id, $session_path );
  
  if ( $action ne 'logout' ) {
    if ( !$c->session_expires && $c->sessionid ) {
      $c->log->info ( "Session '" . $c->sessionid . "' has expired." );
    }

    if ( $action ne 'login' ) {
      $session      = $c->session;
      $session_id   = $c->sessionid;
      $session_path = $self->session_path ( $c );
    }
  }
  
  #
  # Roles.
  #
  
  my ( $user_r, $role );
  
  if ( $action !~ /^(login|logout)$/ ) {
    if ( $user_r = $c->model ( 'App' )->user_r ( $c ) ) {
      $role->{$_} = $user_r->assert_user_role ( $_ ) for qw( can_commit_datasheet can_commit_specification can_test_js can_checkout_specification can_checkout_datasheet can_bofh );
    }
  }
  
  #
  # Class.
  #
  
  my $class;

  if ( $c->user_exists ) {
    $class->{Login} = 'unavailable';

    delete $class->{Logout};
  }
  else {
    $class->{$_} = 'unavailable' for qw( Component Product Status Abstract Logs Diff Subversion Download Logout );

    delete $class->{Login};
  }

  if ( $session ) {
    $class->{Status}     = 'unavailable' unless   $session->{xls_file};
    $class->{Logs}       = 'unavailable' unless   $session->{xls_file} || $session->{mif_file};
    $class->{Abstract}   = 'unavailable' unless   $session->{xls_file} && $session->{mif_file} && $session->{abstract_file};
    $class->{Download}   = 'unavailable' unless   $session->{xls_file} || $session->{mif_file};
    $class->{Subversion} = 'unavailable' unless ( $session->{xls_file} && $session->{mif_file} ) && $session->{svn_component_revision} && $session->{svn_product_revision} && $role->{can_checkout_specification} && $role->{can_commit_specification};
  }

  if ( $action ne 'logout' ) {
    $class->{ucfirst $action} = 'hilited';
  }
  
  #
  # Logs.
  #
  
  my $log_files;
  
  if ( $session_path ) {
    $log_files = [ grep { -f "$session_path/$_" } map { "$_.log" } @{$c->config->{log_stems}} ];
  }
  else {
    $log_files = [];
  }
    
  #
  # Stash.
  #
  
  ( my $title = ucfirst lc $action ) =~ s/\/(\w)/'::' . uc $1/eg;
  
  $c->stash (
    title        => $title,
    class        => $class,
    
    log_files    => $log_files,
    session_id   => $session_id,
    session_path => $session_path,
    user_r       => $user_r,
    role         => $role,
    
    version      => { SOCK => $SOCK::VERSION, iSOCK => $iSOCK::VERSION },
  );
}

sub upload : Private {
  my ( $package, $c, $p, $log, $extension, $whatever ) = @_;
  
  $log->say_n_right ( "Uploading $whatever..." );

  if ( my $uploaded_file = _upload_core ( $c, $p, $log, $extension ) ) {
    $log->left_n_say ( "Done." );
    
    return $uploaded_file;
  }
  else {
    $log->yell ( "Could not upload '" . $c->request->parameters->{$p} . "' \U$extension\E file." );

    $log->left_n_say ( "Failed!" );
  }
  
  return;
}

sub _upload_core : Private {
  my ( $c, $p, $log, $extension ) = @_;
  
  if ( my $upload = $c->request->upload ( $p ) ) {
    my $filename = $upload->filename;
    my $basename = $upload->basename;
    my $target   = $c->session->{session_path} . "/$basename";

    if ( $extension && $filename !~ /\.$extension(\.gz)?$/ ) {
      $log->yell ( "Wrong file extension '$filename' (should be '$extension')!" );
      
      return;
    }
    
    if ( $upload->copy_to ( $target ) ) {
      $log->say ( "Copied '$filename' to '$target'." );
    }
    else {
      $log->expire ( "Failed to copy '$filename' to '$target': $!!" );
    }
    
    return $basename;
  }
  
  return;
}

sub session_path : Private { # FIXME factorize with iSOCK::Model::Root::session_path
  my ( $package, $c ) = @_;
  
  my $session_path = $c->session->{session_path};
  
  unless ( $session_path && -d $session_path ) {
    _mkdir ( $session_path = $c->config->{directory}->{tmp} . '/' . $c->sessionid );
    
    $c->session->{session_path} = $session_path;
  }
  
  $session_path;
}

sub _mkdir : Private { # FIXME factorize with iSOCK::Model::Root::_mkdir
  my $dir = shift;
  
  system "mkdir -p $dir" unless -d $dir; # FIXME use File::Path instead
  
  $dir;
}

sub _isoish : Private {
  sprintf ( "%d-%02d-%02d_%02d:%02d:%02d", @_ );
}

sub bounce_to : Private {
  my ( $self, $c, $to ) = @_;
    
  if ( $to eq '/login' ) {
    $c->flash->{pre_login_uri} ||= $c->request->uri;
  }
  
  $c->response->redirect ( $c->uri_for ( $to ) );
  $c->detach;
}

sub check_user_authorization : Private {
  my ( $self, $c, $required_role ) = @_;
  
  if ( $c->user ) {
    if ( my $user_r = $c->model ( 'App::User' )->find ( $c->user ) ) {
      my $role = { $required_role => $user_r->assert_user_role ( $required_role ) };

      unless ( $role->{$required_role} ) {
        $self->bounce_to ( $c => '/logout' );
      }

      $c->stash ( role => $role );
    }
    else {
      $self->bounce_to ( $c => '/login' );
    }
  }
  else {
    $self->bounce_to ( $c => '/login' );
  }
}

sub _htmlize_lol : Private {
  my ( $self, $lol ) = @_;
  
  no warnings 'uninitialized';
  
  for ( @$lol ) {
    $_ = "<a"    . ( $_->{id} ? " id=\"$_->{id}\"" : "" ) . ( $_->{class} ? " class=\"$_->{class}\"" : "" ) . " href=\"$_->{href}\"" . ( $_->{title} ? " title=\"$_->{title}\"" : "" ) . ">$_->{content}</a>"    for grep { ref eq 'HASH' && $_->{tag} eq 'a'    } @$_;
    $_ = "<span" . ( $_->{id} ? " id=\"$_->{id}\"" : "" ) . ( $_->{class} ? " class=\"$_->{class}\"" : "" ) .                          ( $_->{title} ? " title=\"$_->{title}\"" : "" ) . ">$_->{content}</span>" for grep { ref eq 'HASH' && $_->{tag} eq 'span' } @$_;
  }

  use warnings;

  return $lol;
}

=head1 AUTHOR

Xavier Caron

=head1 LICENSE

This library is free software, you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

1;
